﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;

namespace IETTortak
{
    public class ServiceParser
    {
        private static CultureInfo ci = new CultureInfo("tr-TR");

        private static Regex reSaatTable = new Regex(@"<center>.*?<br>\s*(?<hatName>.*?)\s*</b> hattı<br>Gidiş-Dönüş sefer süresi: (?<gidisDonusSeferSuresi>\d*)\sdakika\.(?<hatTuru>.*?)</center>.*?<td colspan=.><center><b>(?<kalkis>.*?)\s*Kalk.*?<td colspan=.><center><b>(?<varis>.*?)\s*Kalk.*?</tr>.*?</tr>(?<saatler>.*?)</table><p class=text><b>Not</b>:(?<diger>.*?)</td></tr></table.*?Güncelleme Tarihi:</i>(?<updated>\d\d-\d\d-\d\d\d\d)</font>", RegexOptions.Singleline);
            //new Regex(@"<center>.*?<br>\s*(?<hatName>.*?)\s*</b> hattı<br>Gidiş-Dönüş sefer süresi: (?<gidisDonusSeferSuresi>\d*)\sdakika\.(?<hatTuru>.*?)</center>.*?<td colspan=1><center>(?<kalkis>.*?)\s*<br>Kalk.*?<td colspan=1><center>(?<varis>.*?)\s*<br>Kalk.*?</tr>.*?</tr>(?<saatler>.*?)</table><p class=text><b>Not</b>:(?<diger>.*?)</td></tr></table.*?Güncelleme Tarihi:</i>(?<updated>\d\d-\d\d-\d\d\d\d)</font>", RegexOptions.Singleline);

        //groups:
        /*
         * hatName
         * gidisDonusSeferSuresi
         * kalkis
         * varis
         * saatler
         * diger
         * updated
         * 
         */

        private static Regex reSaatlerGetRow = new Regex(@"<tr bgcolor=><center>(?<row>.*?)</tr>", RegexOptions.Singleline);

        private static Regex reSaatlerGetItem = new Regex(@"<font color=(?<renk>.*?)>(?<saat>.*?)</font>", RegexOptions.Singleline);

        private static Regex reNotlar = new Regex(@"<font color=(?<renk>.*?)>(?<not>.*?)</font>", RegexOptions.Singleline);

        private static Dictionary<string, string> sozluk = InitDictionary();

        private static Dictionary<string, string> InitDictionary()
        {
            Dictionary<string, string> ret = new Dictionary<string, string>();

            ret.Add("#ff0000", "kirmizi");
            ret.Add("#FF0000", "kirmizi");
            ret.Add("#008000", "yeþil");
            ret.Add("yeþýl", "yeþil");
            ret.Add("#0000ff", "mavi");
            ret.Add("#0000FF", "mavi");
            ret.Add("#800080", "mor");
            ret.Add("black", "siyah");
            ret.Add("red", "kirmizi");
            ret.Add("#000000", "");

            return ret;
        }

        private static string Translate(string str)
        {
            foreach (string key in sozluk.Keys)
            {
                str = str.Replace(key, sozluk[key]);
            }
            return str;
        }

        public static Service Parse(string serviceCode, string saatlerRaw)
        {
            
            //groups:
            /*
             * hatName
             * gidisDonusSeferSuresi
             * kalkis
             * varis
             * saatler
             * diger
             * updated
             * 
             */
            Service ret = new Service();

            try
            {

                Match m = reSaatTable.Match(saatlerRaw);

                ret.ServiceCode = serviceCode;
                ret.ServiceName = m.Groups["hatName"].ToString();
                ret.Duration = int.Parse(m.Groups["gidisDonusSeferSuresi"].ToString());
                //kalkis = m.Groups["kalkis"].ToString();
                //varis = m.Groups["varis"].ToString();
                string diger = Translate(m.Groups["diger"].ToString().ToLower().Trim());
                string hatTuru = m.Groups["hatTuru"].ToString().Replace("<br>", "").Replace("<b>", "").Replace("</b>", "").Trim();


                diger = diger.Replace("<font color=siyah><font color=kirmizi><u><font color=kirmizi><u> altı-çizgili ve kırmızı servisler </u></font></u></font></font> öho (özel halk otobüsü) servisidir.", "").Trim();

                diger = diger.Replace("<font color=siyah><font color=kirmizi><u> altı-çizgili ve kırmızı servisler </u></font></font> öho (özel halk otobüsü) servisidir.", "").Trim();

                MatchCollection notlar = reNotlar.Matches(diger);
                StringBuilder sbNotlar = new StringBuilder();
                if (hatTuru.Length > 0)
                    sbNotlar.AppendLine(hatTuru);
                foreach (Match mNot in notlar)
                {
                    if (mNot.Groups["renk"].ToString().Length > 0)
                    {
                        sbNotlar.Append(mNot.Groups["renk"].ToString());
                        sbNotlar.Append(": ");
                    }
                    sbNotlar.AppendLine(mNot.Groups["not"].ToString());
                }
                diger = sbNotlar.ToString();

                ret.Notlar = diger;

                string saatler = Translate(m.Groups["saatler"].ToString());
                ret.LastUpdated = DateTime.Parse(m.Groups["updated"].ToString(), ci);

                ret.ServiceTimes = new List<ServiceTime>();

                MatchCollection saatRows = reSaatlerGetRow.Matches(saatler);

                foreach (Match mRow in saatRows)
                {
                    MatchCollection items = reSaatlerGetItem.Matches(mRow.Groups["row"].ToString());
                    //items.Count = 6 olmalý,  her zaman.

                    for (int i = 0; i < 6; i++)
                    {
                        if (items[i].Groups["saat"].ToString().Length == 0) continue;

                        switch (i)
                        {
                            case 0:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.İşgünü, ServiceTime.ReturningEnum.Gidiş));
                                break;
                            case 1:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.İşgünü, ServiceTime.ReturningEnum.Dönüş));
                                break;
                            case 2:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.Cumartesi, ServiceTime.ReturningEnum.Gidiş));
                                break;
                            case 3:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.Cumartesi, ServiceTime.ReturningEnum.Dönüş));
                                break;
                            case 4:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.PazarTatil, ServiceTime.ReturningEnum.Gidiş));
                                break;
                            case 5:
                                ret.ServiceTimes.Add(new ServiceTime(items[i].Groups["renk"].ToString(), items[i].Groups["saat"].ToString(), ServiceTime.DayTypeEnum.PazarTatil, ServiceTime.ReturningEnum.Dönüş));
                                break;
                        }
                    }
                }

                return ret;
            }
            catch (Exception ex)
            {
                throw new ArgumentException(string.Format("ServiceParser: Regex cannot match the input: {0}", serviceCode), ex);
            }
        }
    }

    public class Service
    {
        private string serviceCode;

        public string ServiceCode
        {
            get { return serviceCode; }
            set { serviceCode = value; }
        }
        private string serviceName;

        public string ServiceName
        {
            get { return serviceName; }
            set { serviceName = value; }
        }
        private int duration;

        public int Duration
        {
            get { return duration; }
            set { duration = value; }
        }
        private string notlar;

        public string Notlar
        {
            get { return notlar; }
            set { notlar = value; }
        }

        private int routeID;

        public int RouteID
        {
            get { return routeID; }
            set { routeID = value; }
        }

        private DateTime lastUpdated;

        public DateTime LastUpdated
        {
            get { return lastUpdated; }
            set { lastUpdated = value; }
        }

        private List<ServiceTime> serviceTimes;

        public List<ServiceTime> ServiceTimes
        {
            get { return serviceTimes; }
            set { serviceTimes = value; }
        }


        public Service() { }

    }

    public class ServiceTime
    {
        public static string GetDayType(ServiceTime st)
        {
            switch (st.DayType)
            {
                case DayTypeEnum.Cumartesi:
                    return "C";
                case DayTypeEnum.İşgünü:
                    return "İ";
                case DayTypeEnum.PazarTatil:
                    return "P";
            }
            return null;
        }

        public static DayTypeEnum GetDayType(char dt)
        {
            switch (dt)
            {
                case 'C':
                    return DayTypeEnum.Cumartesi;
                case 'İ':
                    return DayTypeEnum.İşgünü;
                case 'I':
                    return DayTypeEnum.İşgünü;
                case 'P':
                    return DayTypeEnum.PazarTatil;
            }
            return DayTypeEnum.İşgünü;
        }

        public enum DayTypeEnum // İ C P
        {
            İşgünü,
            Cumartesi,
            PazarTatil
        }

        public enum ReturningEnum
        {
            Gidiş = 0,
            Dönüş = 1
        }

        public enum VehicleTypeEnum
        {
            IETT = 1,
            ÖHO = 2
        }

        private ReturningEnum returning;

        public ReturningEnum Returning
        {
            get { return returning; }
            set { returning = value; }
        }
        private DayTypeEnum dayType; // İ C P

        public DayTypeEnum DayType
        {
            get { return dayType; }
            set { dayType = value; }
        }
        private Int16 time; // HH * 60 + mm

        public Int16 Time
        {
            get { return time; }
            set { time = value; }
        }
        private VehicleTypeEnum vehicleType;

        public VehicleTypeEnum VehicleType
        {
            get { return vehicleType; }
            set { vehicleType = value; }
        }
        private string fontColor;

        public string FontColor
        {
            get { return fontColor; }
            set { fontColor = value; }
        }

        private string mark;
        public string Mark
        {
            get { return mark; }
            set { mark = value; }
        }

        public ServiceTime() { }

        private short TimeToInt(string s)
        {
            if (s.Length != 5) throw new ArgumentException("Time must be in HH:mm format.");
            short ret = short.Parse(s.Substring(0, 2));
            ret *= 60;
            ret += short.Parse(s.Substring(3, 2));
            return ret;
        }

        public ServiceTime(string color, string time, DayTypeEnum dayType, ReturningEnum returning)
        {
            this.fontColor = color;
            string mark = "";
            vehicleType = VehicleTypeEnum.IETT;
            this.DayType = dayType;
            this.returning = returning;

            if (time.Length > 5)
            {
                if (time.Contains("<font color=kirmizi><u>"))
                {
                    vehicleType = VehicleTypeEnum.ÖHO;
                    time = time.Replace("<font color=kirmizi><u>", "").Replace("</u>", "");
                    fontColor = "kırmızı";
                    mark = "altı çizgili";
                }

                int i = 0;
                foreach (char c in time)
                {
                    if (c < '0' || c > '9')
                    {
                        i++;
                        if (c == '¦') //dismiss this character.
                            continue;
                        mark += c.ToString();
                    }
                    else
                    {
                        break;
                    }
                }
                this.mark = mark;
                this.time = TimeToInt(time.Substring(i, 5));
            }
            else
            {
                this.time = TimeToInt(time);
                this.mark = "";
            }
        }

        public static string TimeToString(int time)
        {
            int min = time % 60;
            int hh = time / 60;
            return hh.ToString("00") + ":" + min.ToString("00");
        }

        public string ToCompactString()
        {
            return string.Format("{0}{1}{2}{3}", TimeToString(time), vehicleType == VehicleTypeEnum.IETT ? "i" : "ö", fontColor == "kırmızı" ? "" : fontColor, mark == "altı çizgili" ? "" : mark);
        }
    }

    //ServiceDatabaseHelper

    public class ServiceDatabaseHelper
    {
        private static CultureInfo ci = new CultureInfo("tr-TR");

        public delegate void UpdateProgressHandler(string key, int tamamlanan, int tümü);
        public event UpdateProgressHandler UpdateProgress;

        private string key;
        public ServiceDatabaseHelper(string key)
        {
            this.key = key;
        }

        protected void OnUpdateProgress(string key, int tamamlanan, int tümü)
        {
            if (UpdateProgress != null)
                UpdateProgress(key, tamamlanan, tümü);
        }

        private static void UpdateRouteID(Service svc)
        {
            svc.RouteID = int.Parse(DAL.ExecScalar("SELECT ISNULL(RouteID, 0) FROM ServiceInfo.tblRoute WHERE Name = @Name AND RouteTime = @Duration", false, "@Name", svc.ServiceName, "@Duration", svc.Duration).ToString());
        }

        public static Service LoadService(string serviceCode)
        {
            Service ret = new Service();
            if ("0" ==
                DAL.ExecScalar("ServiceInfo.uspExistsService", true, "@ServiceCode", serviceCode).ToString())
            {
                ret.ServiceName = "Servis bulunamadı.";
                return ret;
            }
            else
            {
                DataView dv = DAL.GetDataTable("Service", true, "ServiceInfo.uspGetService", "@ServiceCode", serviceCode).DefaultView;
                if (dv.Count == 1)
                {
                    ret.LastUpdated = DateTime.Parse(dv[0]["LastUpdated"].ToString(), ci);
                    ret.Duration = int.Parse(dv[0]["Duration"].ToString());
                    ret.Notlar = dv[0]["Notes"].ToString();
                    ret.ServiceCode = dv[0]["Code"].ToString();
                    ret.ServiceName = dv[0]["Name"].ToString();
                    ret.RouteID = int.Parse(dv[0]["RouteId"].ToString());
                    // get service times

                    DataView dvServiceTimes = DAL.GetDataTable("ServiceTimes", true, "ServiceInfo.uspGetServiceTimes", "@ServiceCode", ret.ServiceCode).DefaultView;
                    ret.ServiceTimes = new List<ServiceTime>(300);
                    foreach (DataRowView drv in dvServiceTimes)
                    {
                        ret.ServiceTimes.Add(
                            new ServiceTime
                            {
                                DayType = ServiceTime.GetDayType(drv["DayTypeId"].ToString()[0]),
                                Returning = (ServiceTime.ReturningEnum)(bool.Parse(drv["Returning"].ToString()) ? 1 : 0),
                                Time = short.Parse(drv["Time"].ToString()),
                                VehicleType = (ServiceTime.VehicleTypeEnum)int.Parse(drv["VehicleType"].ToString()),
                                Mark = drv["Mark"].ToString(),
                                FontColor = drv["FontColor"].ToString()
                            });
                    }
                }
            }


            return ret;
        }

        public void AddServiceListToDB(List<Service> lst)
        {
            try
            {

                SqlConnection sqlConn = new SqlConnection(DAL.GetConnectionString());
                sqlConn.Open();

                SqlCommand cmdAddService = new SqlCommand("ServiceInfo.uspAddService", sqlConn);
                cmdAddService.CommandType = CommandType.StoredProcedure;
                cmdAddService.Parameters.Add("@Code", SqlDbType.NVarChar);
                cmdAddService.Parameters.Add("@Duration", SqlDbType.Int);
                cmdAddService.Parameters.Add("@Notes", SqlDbType.NVarChar);
                cmdAddService.Parameters.Add("@RouteId", SqlDbType.Int);
                cmdAddService.Parameters.Add("@LastUpdated", SqlDbType.DateTime);

                SqlCommand cmdServiceTime = new SqlCommand("INSERT INTO ServiceInfo.tblServiceTime (ServiceCode, Time, DayTypeID, FontColor, Mark, Returning, VehicleType) VALUES (@ServiceCode, @Time, @DayTypeID, @FontColor, @Mark, @Returning, @VehicleType)", sqlConn);
                cmdServiceTime.Parameters.Add("@ServiceCode", SqlDbType.NVarChar);
                cmdServiceTime.Parameters.Add("@Time", SqlDbType.Int);
                cmdServiceTime.Parameters.Add("@DayTypeId", SqlDbType.Char);
                cmdServiceTime.Parameters.Add("@FontColor", SqlDbType.NVarChar);
                cmdServiceTime.Parameters.Add("@Mark", SqlDbType.NVarChar);
                cmdServiceTime.Parameters.Add("@Returning", SqlDbType.Bit);
                cmdServiceTime.Parameters.Add("@VehicleType", SqlDbType.Int);


                int tamamlanan = 0;
                foreach (Service svc in lst)
                {
                    UpdateRouteID(svc);
                    if (svc.RouteID > 0)
                    {
                        //DAL.ExecNonQuery("ServiceInfo.uspAddService", true, "@Code", svc.ServiceCode, "@Duration", svc.Duration, "@Notes", svc.Notlar, "@RouteID", svc.RouteID, "@LastUpdated", svc.LastUpdated.ToString("s"));

                        cmdAddService.Parameters["@Code"].Value = svc.ServiceCode;
                        cmdAddService.Parameters["@Duration"].Value = svc.Duration;
                        cmdAddService.Parameters["@Notes"].Value = svc.Notlar;
                        cmdAddService.Parameters["@RouteId"].Value = svc.RouteID;
                        cmdAddService.Parameters["@LastUpdated"].Value = svc.LastUpdated;
                        
                        cmdAddService.ExecuteNonQuery();

                        foreach (ServiceTime st in svc.ServiceTimes)
                        {
                            cmdServiceTime.Parameters["@ServiceCode"].Value = svc.ServiceCode;
                            cmdServiceTime.Parameters["@Time"].Value = st.Time;
                            cmdServiceTime.Parameters["@DayTypeId"].Value = ServiceTime.GetDayType(st);
                            cmdServiceTime.Parameters["@FontColor"].Value = st.FontColor;
                            cmdServiceTime.Parameters["@Mark"].Value = st.Mark;
                            cmdServiceTime.Parameters["@Returning"].Value = (bool)(st.Returning == ServiceTime.ReturningEnum.Gidiş);
                            cmdServiceTime.Parameters["@VehicleType"].Value = (int)st.VehicleType;
                            cmdServiceTime.ExecuteNonQuery();

                            //DAL.ExecNonQuery("INSERT INTO ServiceInfo.tblServiceTime (ServiceCode, Time, DayTypeID, FontColor, Mark, Returning, VehicleType) VALUES (@ServiceCode, @Time, @DayTypeID, @FontColor, @Mark, @Returning, @VehicleType)", false, "@ServiceCode", svc.ServiceCode, "@Time", st.Time, "@DayTypeID", ServiceTime.GetDayType(st), "@FontColor", st.FontColor, "@Mark", st.Mark, "@Returning", (bool)(st.Returning == ServiceTime.ReturningEnum.Gidiş), "@VehicleType", (int)st.VehicleType);
                        }
                        tamamlanan++;
                        OnUpdateProgress(key, tamamlanan, lst.Count);
                    }
                    else
                    {
                        //problem++;
                    }
                }
                sqlConn.Close();
            }
            catch (SqlException se)
            {

            }
        }
    }


}
